#define _GUN_SOURCE
#include "app_bt.h"
#include "string.h"
#include "log/log.h"
#include "unistd.h"
#include "app_serial.h"

static char read_buf[1024];
static int read_len = 0;
static char fix_header[2] = {0xf1, 0xdd};
/**
 * @brief 移除数据
 * 
 * @param len   需要移除的长度
 */
static void remove_data(int len)
{
    memmove(read_buf, read_buf + len, read_len - len);
    read_len -= len;
}

static int init_bt_config(Device *device)
{
    //初始化串口
    app_serial_init(device);
    //设置串口为非阻塞模式
    app_serial_setBlock(device, 0);
    app_serial_flush(device);
    //判断蓝牙是否可用 -> 说明当前蓝牙波特率为9600
    if (app_bt_status(device) == 0)
    {
        log_info("当前蓝牙波特率为9600");
        //设置波特率为115200
        app_bt_set_baudRate(device, BT_BR_115200); //设置波特率为115200
        
        app_bt_rename(device, "Core");  //设置蓝牙名称
        app_bt_restart(device); //重启蓝牙
        //等待蓝牙重启
        sleep(2);
    }
    //修改串口为115200
    app_serial_setBaudRate(device, BR_115200);
    app_serial_flush(device);
    // 检查蓝牙是否可用，如果不可用，说明蓝牙初始化失败
    if (app_bt_status(device) != 0) {
        log_debug("蓝牙初始化失败");
        return -1;
    }

    app_bt_setNetid(device, "2025"); // 设置蓝牙的NETID
    app_bt_setMacAddr(device, "1424"); // 设置蓝牙的MADDR

    // 将串口改为阻塞模式
    app_serial_setBlock(device, 1);
    app_serial_flush(device);

    log_debug("蓝牙初始化成功");
    return 0;
    // //检查蓝牙是否可用
    // if (app_bt_status(device) == 0)
    // {
    //     log_debug("蓝牙初始化成功");
    //     app_bt_setNetid(device, "2025"); //设置网卡ID
    //     app_bt_setMacAddr(device, "0203"); //设置MAC地址
    //     //设置串口为阻塞模式
    //     app_serial_setBlock(device, 1);
    //     app_serial_flush(device);
    //     return 0;
    // }
    // else
    // {
    //     log_error("蓝牙初始化失败");
    //     return -1;
    // }
}

int app_bt_init(Device *device)
{
    // 将蓝牙实现的读后处理函数 ，写前处理函数交给设备
    device->pre_write = app_bt_preWrite;
    device->post_read = app_bt_postRead;
    //初始化蓝牙相关配置
    
    return init_bt_config(device);
}

/**
    字符数组消息: 
        例子：1 2 3 XX abc
        格式：conn_type id_len msg_len id msg
    蓝牙发送数据格式例子：
        例子：
        41 54 2b 4d 45 53 48 00： AT+MESH（固定头部）
        ff ff: 对端的MADDR（如果是FFFF代表群发）
        61 62 63: 要发送的数据（不超过12字节）
        0d 0a：\r\n（固定结尾）
        AT+MESH XX abc \r\n
 */
int app_bt_preWrite(char *data, int len)
{
    // 检查data长度
    if (len  < 6)
    {
        log_error("字符数组符串长度不能小于6");
        return -1;
    }
    
    //计算蓝牙数据的长度 blue_len
    int blue_len = 8 + 2 + data[2] + 2;
    //创建蓝牙数据的数组  blue_data
    char blue_data[blue_len];
    //填充蓝牙数据到 blue_data中
    memcpy(blue_data, "AT+MESH", 8);            //固定头部AT+MESH
    memcpy(blue_data + 8, data + 3, 2);         //id
    memcpy(blue_data + 10, data + 5, data[2]);  //msg
    memcpy(blue_data + 10 + data[2], "\r\n", 2);          //固定结尾
    //清空data数据
    memset(data, 0, len);
    //将blue_data数据拷贝到data中
    memcpy(data, blue_data, blue_len);
    return blue_len;
}

/**
    接收方得到数据（3 + [2]）：f1 dd 07 23 23 ff ff 41 42 43
        f1 dd : 固定的头部
        07： 之后数据的长度（5-16之间） 
        23 23：对端（发送方）的MADDR
        ff ff: 我的MADDR或ffff(群发)
        41 42 43：发送的数据 
    处理后的数据格式：conn_type id_len msg_len id msg
    问题： 完整的蓝牙数据可能需要多次读取才能得到
    解决： 将读取的数据保存起来，同时判断是否已经接受到一个完整的蓝牙数据
 */

int app_bt_postRead(char *data, int len)
{
    // 将数据保存起来
    memcpy(read_buf + read_len, data, len);
    read_len += len;
    memset(data, 0, len);
    // 判断是否已经接受到一个完整的蓝牙数据 -> 继续读取
    if (read_len < 8)
    { 
        log_debug("还未接收完整的蓝牙数据，继续读取");
        return 0; 
    }
    // 进一步检查处理，需要遍历
    int i;
    for (i = 0; i < read_len - 7; i++)
    {
        // 检查fix_header头部
        if (memcmp(read_buf + i, fix_header, 2) == 0)
        { 
            //如果i>0,说明之前是无用的数据，需要丢弃
            if (i > 0)
            {
                log_debug("丢弃无用的数据");
                remove_data(i);
            }
            //判断数据的完整性
            int bule_len = read_buf[2] + 3;
            if(read_len < bule_len)
            {
                log_debug("数据不完整，继续读取");
                return 0;
            }
            log_debug("数据完整，开始处理");
            // 处理数据,向data中添加字符数组消息
            data[0] = 1;                               //conn_type
            data[1] = 2;                               //id_len
            data[2] = read_buf[2] - 4;                 //msg_len
            memcpy(data + 3, read_buf + 3, 2);         //id
            memcpy(data + 5, read_buf + 7, data[2]);   //msg
            //释放蓝牙数据
            remove_data(bule_len);
            //返回字符数组消息的长度
            return 3 + 2 + data[2];
        }
    }
    // 如果出来循环， 且 i > 0, 遍历的数据都是无用数据，需要丢弃
    if (i > 0)
    {
        log_debug("丢弃无用的数据");
        remove_data(i);
    }
    return 0;
}

//等待返回ack
int wait_ack(int fd)
{
    //等待一定的时间，让蓝牙能返回响应数据
    usleep(50 * 1000);
    // 读取响应数据
    char data_buf[4];
    read(fd, data_buf, 4);
    // 判断响应数据
    if (memcmp(data_buf, "OK\r\n", 4) == 0)
    {
        return 0;
    }
    else
    {
        log_error("蓝牙响应数据失败");
        return -1;
    }
}
int app_bt_status(Device *device)
{
    // 发送AT命令
    char *cmd = "AT\r\n";
    //将指令写入串口文件， 发送给蓝牙
    write(device->fd, cmd, strlen(cmd));
    //接收ACK，判断是否成功
    return wait_ack(device->fd);
}
int app_bt_set_baudRate(Device *device, BT_BardRate rate)
{
    // 发送AT命令
    char cmd[20];
    sprintf(cmd, "AT+BAUD%c\r\n", rate);
    //将指令写入串口文件， 发送给蓝牙
    write(device->fd, cmd, strlen(cmd));
    //接收ACK，判断是否成功
    return wait_ack(device->fd);
}
int app_bt_rename(Device *device, char *name)
{
    // 发送AT命令
    char cmd[20];
    sprintf(cmd, "AT+NAME%s\r\n", name);
    //将指令写入串口文件， 发送给蓝牙
    write(device->fd, cmd, strlen(cmd));
    //接收ACK，判断是否成功
    return wait_ack(device->fd);
}
int app_bt_setNetid(Device *device, char *netid)
{
    // 发送AT命令
    char cmd[20];
    sprintf(cmd, "AT+NETID%s\r\n", netid);
    //将指令写入串口文件， 发送给蓝牙
    write(device->fd, cmd, strlen(cmd));
    //接收ACK，判断是否成功
    return wait_ack(device->fd);
}
int app_bt_setMacAddr(Device *device, char *macaddr)
{
    // 发送AT命令
    char cmd[20];
    sprintf(cmd, "AT+MADDR%s\r\n", macaddr);
    //将指令写入串口文件， 发送给蓝牙
    write(device->fd, cmd, strlen(cmd));
    //接收ACK，判断是否成功
    return wait_ack(device->fd);
}
int app_bt_restart(Device *device)
{
    // 发送AT命令
    char *cmd = "AT+RESET\r\n";
    //将指令写入串口文件， 发送给蓝牙
    write(device->fd, cmd, strlen(cmd));
    //接收ACK，判断是否成功
    return wait_ack(device->fd);
}
// echo -n -e "\xf9\xf9\x01\x01\x33\x33" >>serial_test
// echo -n -e "\x00\x00\x00\xff\xf1\xdd" >>serial_test
// echo -n -e "\x07\x23\x23\xff\xff\x41" >>serial_test
// echo -n -e "\x42\x43\x88\x00\x99\x41" >>serial_test
